package su.example.sms.service.impl;

import liquibase.util.StringUtil;
import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.jpa.HibernateEntityManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import su.example.sms.domain.entity.Student;
import su.example.sms.repository.StudentRepository;
import su.example.sms.service.StudentService;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {

    @Resource
    private StudentRepository studentRepository;

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Student createStudent(Student student) {
        return studentRepository.save(student);
    }

    @Override
    public Student updateStudent(Student student) {
        Optional<Student> existedStudentOptional = studentRepository.findById(student.getId());
        if (existedStudentOptional.isPresent()) {
            Student existedStudent = existedStudentOptional.get();
            if (!StringUtils.isEmpty(student.getName())) {
                existedStudent.setName(student.getName());
            }
            if (!StringUtil.isEmpty(student.getStudentId())) {
                existedStudent.setStudentId(student.getStudentId());
            }
            if (!StringUtil.isEmpty(student.getClassId())) {
                existedStudent.setClassId(student.getClassId());
            }
            if (!StringUtil.isEmpty(student.getGender())) {
                existedStudent.setGender(student.getGender());
            }
            return studentRepository.save(existedStudent);

        }
        throw new RuntimeException(String.format("需要更新的学生: %s 不存在", student.getId()));
    }


    @Override
    public void deleteStudent(String id) {
        Optional<Student> existedStudentOptional = studentRepository.findById(id);
        if (existedStudentOptional.isPresent()) {
            studentRepository.deleteById(id);
            return;
        }
        throw new RuntimeException(String.format("需要删除的学生: %s 不存在", id));
    }

    @Override
    public List<Student> findAllStudents() {
        return studentRepository.findAll();
    }

    @Override
    public Student findStudentById(String id) {
        Optional<Student> existedStudentOptional = studentRepository.findById(id);
        if (existedStudentOptional.isPresent()) {
            return existedStudentOptional.get();
        }
        throw new RuntimeException(String.format("查询的学生: %s 不存在", id));
    }

    @Override
    public Page<Student> queryStudent(Student student, Pageable pageable) {
        Criteria criteria = ((HibernateEntityManager) entityManager).getSession().createCriteria(Student.class);

        if (student.getName() != null && !student.getName().trim().isEmpty()) {
            criteria.add(Restrictions.like("name", student.getName(), MatchMode.ANYWHERE));
        }
        if (student.getStudentId() != null && !student.getStudentId().trim().isEmpty()) {
            criteria.add(Restrictions.like("studentId", student.getStudentId(), MatchMode.ANYWHERE));
        }
        if (student.getClassId() != null && !student.getClassId().trim().isEmpty()) {
            criteria.add(Restrictions.like("classId", student.getClassId(), MatchMode.ANYWHERE));
        }
        if (student.getGender() != null && !student.getGender().trim().isEmpty()) {
            criteria.add(Restrictions.like("gender", student.getGender(), MatchMode.ANYWHERE));
        }

        int pageNum = pageable.getPageNumber();
        int pageSize = pageable.getPageSize();

        @SuppressWarnings("unchecked")
        List<Student> list = (List<Student>) criteria
                .setFirstResult(pageNum * pageSize)
                .setMaxResults(pageSize).list();

        int totalResult = ((Number) criteria
                .setFirstResult(0)
                .setProjection(Projections.rowCount())
                .uniqueResult())
                .intValue();
        return new PageImpl<>(list, pageable, totalResult);
    }
}
